package com.cs410.collabwriting.junit.servlets;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

import junit.framework.Assert;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;

import com.cs410.collabwriting.main.Story;
import com.cs410.collabwriting.main.StoryManager;
import com.cs410.collabwriting.main.TagManager;
import com.cs410.collabwriting.main.User;
import com.cs410.collabwriting.main.UserManager;
import com.cs410.collabwriting.servlets.UpdateHandler;
import com.cs410.collabwriting.test.DatabaseUtility;
import com.cs410.collabwriting.tools.DatabaseManager;
import com.cs410.collabwriting.tools.LogManager;
import com.cs410.collabwriting.tools.queryTools.DatabaseTable;
import com.cs410.collabwriting.tools.queryTools.QueryBuilder;
import com.cs410.collabwriting.tools.queryTools.QueryCondition;
import com.cs410.collabwriting.tools.queryTools.QueryType;
import com.cs410.collabwriting.tools.queryTools.tables.STORYLISTNAME_TABLE;
import com.cs410.collabwriting.tools.queryTools.tables.STORYLIST_TABLE;

public class UpdateHandlerTest extends UpdateHandler{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	@Rule
	public transient TestName m_testName = new TestName();
	public static String m_userInfo = "USER_HANDLER_TEST";
	public static User m_user;
	public static Story m_story;
	private static HttpClient httpclient = new DefaultHttpClient();
	
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		LogManager.logInfo("[JUnitTest] -- Starting JUnit Tests for UpdateHandler" );
		DatabaseUtility.DeleteAllTables();
		Thread.sleep(1000);
		DatabaseUtility.CreateAllTables();
		Thread.sleep(1000);
		DatabaseUtility.CreateAllTestingData();
		Thread.sleep(15000);
		
		m_user = UserManager.getInstance().addUser( m_userInfo, m_userInfo, m_userInfo);
		m_user.activateUser( m_user.getUserID(), m_user.getActivateKey() );
		m_story = StoryManager.getInstance().createStory( "UPDATE_HANDLER_TEST", m_user.getUserID(), null );
		m_story.contributePost( m_user.getUserID(), "ABCDEFG");
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
		DatabaseUtility.DeleteAllTables();
		LogManager.logInfo("[JUnitTest] -- Finished JUnit Tests for UpdateHandler" );
	}

	@Before
	public void setUp() throws Exception {
		LogManager.logInfo("[JUnitTest] -- Starting Test : " + m_testName.getMethodName() );
	}

	@After
	public void tearDown() throws Exception {
		LogManager.logInfo("[JUnitTest] -- Finished Test : " + m_testName.getMethodName() );
	}

	@Test
	public void createAndUpdateStoryListTest() throws InterruptedException {
		boolean created = StoryManager.getInstance().createStorylist( m_testName.getMethodName(), m_user.getUserID() );
		Assert.assertTrue( created );
		
		Thread.sleep( 2000 );
		
		JSONObject json = new JSONObject();
		this.AddStoryToStorylists( json, m_user.getUserID(), m_story.getStoryID() + "", new String[]{m_testName.getMethodName() });

        ArrayList<String[]> lists = DatabaseManager.executeQuery(
            new QueryBuilder(QueryType.SELECTION)
            .addColumns(DatabaseTable.STORYLIST_TABLE + "." + STORYLIST_TABLE.STORYID)
            .addTables(DatabaseTable.STORYLIST_TABLE, DatabaseTable.STORYLISTNAME_TABLE)
            .addConditions(QueryCondition.AND, DatabaseTable.STORYLIST_TABLE + "." + STORYLIST_TABLE.LISTID, QueryCondition.EQ, DatabaseTable.STORYLISTNAME_TABLE + "." + STORYLISTNAME_TABLE.LISTID)
            .addConditions(QueryCondition.AND, DatabaseTable.STORYLISTNAME_TABLE + "." + STORYLISTNAME_TABLE.NAME, QueryCondition.EQ, m_testName.getMethodName()));
		
		Assert.assertEquals( true, lists != null && lists.size() >= 0 );
	}

	@Test
	public void getListforStoryListTest() throws InterruptedException {
		boolean created = StoryManager.getInstance().createStorylist( m_testName.getMethodName(), m_user.getUserID() );
		Assert.assertTrue( created );
		
		Thread.sleep( 2000 );
		JSONObject json = new JSONObject();
		json = this.GetListForStorylist( json, "1");
		Assert.assertTrue(json.toString().contains( "stories" ));
	}
	
	@Test
	public void getListToAddStoryToTest() {
		JSONObject json = new JSONObject();
		json = this.GetListsToAddStoryTo( json, "angie", m_story.getStoryID() + "" );
		Assert.assertTrue(json.toString().contains( "listid" ));
	}
	
	@Test
	public void getPromptListasJSONTest() {
		JSONObject json = new JSONObject();
		json = this.GetPromptListAsJSON( json );
		Assert.assertTrue( json.toString().contains( "promptid" ) );
	}
	
	@Test
	public void getStoryInfoForStoryTest() {
		JSONObject json = new JSONObject();
		json = this.GetStoryInfoForStory( json, m_story.getStoryID() + "", m_user );
		Assert.assertTrue( json.toString().contains( "ABCDEFG" ) );
	}
	
	@Test
	public void getStoryListAsJSONTest() {
		JSONObject json = new JSONObject();
		json = this.GetStoryListAsJSON( json );
		Assert.assertTrue(json.toString().contains("storyid"));
	}
	
	@Test
	public void getStoryListForUserTest() {
		boolean created = StoryManager.getInstance().createStorylist( m_testName.getMethodName(), m_user.getUserID() );
		Assert.assertTrue( created );
		
		JSONObject json = new JSONObject();
		json = this.GetStorylistForUser( json , m_user.getUserID() );
		Assert.assertTrue( json.toString().contains( m_testName.getMethodName() ) );
	}
	
	@Test
	public void getStorySearchResultsAsJSONTest() {
		JSONObject json = new JSONObject();
		json = this.GetStorySearchResultsAsJSON( json, "", "", 1, new String[]{"FANTASY"} , "byvote" );
		Assert.assertTrue( json.toString().contains( "storyid" ) );
	}
	
	@Test
	public void getSubscribedStoriesTest() {
		m_user.subscribeToStory( m_story.getStoryID() );
		JSONObject json = new JSONObject();
		json = this.getSubscribedStories( json, m_user.getUserID() );
		Assert.assertTrue( json.toString().contains( "" + m_story.getStoryID() ) );
	}
	
	@Test
	public void getSubscribedUserTest() {
		m_user.subscribeToWriter( "justine" );
		JSONObject json = new JSONObject();
		json = this.getSubscribedUsers( json , m_user.getUserID());
		Assert.assertTrue( json.toString().contains( "justine") );
	}
	
	@Test
	public void getSubscriptionUpdatesTest() {
		JSONObject json = new JSONObject();
		json = this.GetSubscriptionUpdatesAsJSON( json , m_user.getUserID() );
		Assert.assertTrue( json.toString().contains("newsfeed") );
		Assert.assertTrue( json.toString().contains( "justine" ) );
	}
	
	@Test
	public void getUserTagsTest() {
		JSONObject json = new JSONObject();
		TagManager.getInstance().addTag( m_story.getStoryID(), m_user.getUserID(), "TESTTAG");
		json = this.getUserTags( json, m_user.getUserID(), m_story.getStoryID() );
		Assert.assertTrue( json.toString().contains("TESTTAG") );
	}
	
	@Test
	public void getTopListAsJSONTest() throws JSONException {
	    JSONObject json = new JSONObject();
	    json = this.GetTopVotedListAsJSON(json);
	    JSONArray array = (JSONArray) json.get("stories");
	    Assert.assertNotNull(array);
	    Assert.assertTrue(array.length() <= 10);
        Assert.assertTrue(array.length() > 0);
        
        json = new JSONObject();
        json = this.GetTopViewedListAsJSON(json);
        array = (JSONArray) json.get("stories");
        Assert.assertNotNull(array);
        Assert.assertTrue(array.length() <= 10);
        Assert.assertTrue(array.length() > 0);
	}
	
	@Test
	public void getPromptAsJSONTest() throws JSONException {
        JSONObject json = new JSONObject();
        json = this.GetPromptAsJSON(json, "1");
        Assert.assertEquals(1, json.getInt("promptid") );
	}
	
	@Test
	public void urlRequestParametersTest() throws IOException {
		String URL = "http://localhost:8080/writeonproject/login?user=" + m_userInfo + "&password=" + m_userInfo + "&action=login";
		String response = UpdateHandlerTest.getServletCallResponse( URL );
		Assert.assertTrue( response.contains( "loggedIn\":\"true") );
		
		URL = "http://localhost:8080/writeonproject/update?page=newsfeed";
		response = UpdateHandlerTest.getServletCallResponse( URL );
		Assert.assertTrue( response.contains("error\":\"false") );
		
		URL = "http://localhost:8080/writeonproject/update?page=browse_stories";
		response = UpdateHandlerTest.getServletCallResponse( URL );
		Assert.assertTrue( response.contains("error\":\"false") );
	
		URL = "http://localhost:8080/writeonproject/update?page=browse_prompts";
		response = UpdateHandlerTest.getServletCallResponse( URL );
		Assert.assertTrue( response.contains("error\":\"false") );
		
		URL = "http://localhost:8080/writeonproject/update?page=search_stories&keywords=anything&author=anyone&sortBy=viewcount&tagIndex=1&tag0=abc";
		response = UpdateHandlerTest.getServletCallResponse( URL );
		Assert.assertTrue( response.contains("error\":\"false") );
		
		URL = "http://localhost:8080/writeonproject/update?page=browse_stories_tags&tagIndex=1&tag0=abc";
		response = UpdateHandlerTest.getServletCallResponse( URL );
		Assert.assertTrue( response.contains("error\":\"false") );
		
		URL = "http://localhost:8080/writeonproject/update?page=story_view&storyid=123";
		response = UpdateHandlerTest.getServletCallResponse( URL );
		Assert.assertTrue( response.contains("error\":\"false") );
		
		URL = "http://localhost:8080/writeonproject/update?page=story_view";
		response = UpdateHandlerTest.getServletCallResponse( URL );
		Assert.assertTrue( response.contains("error\":\"true") );
	
		URL = "http://localhost:8080/writeonproject/update?page=story_comment&storyid=2";
		response = UpdateHandlerTest.getServletCallResponse( URL );
		Assert.assertTrue( response.contains("error\":\"false") );
		
		URL = "http://localhost:8080/writeonproject/login?action=logout";
		response = UpdateHandlerTest.getServletCallResponse( URL );
	}
	
	/*
	 * From Lecture Slide Examples
	 */
	private static String getServletCallResponse(String URL) throws IOException {
		HttpGet httpget = new HttpGet(URL);
		httpget.setHeader("Cookie", "JSESSIONID=JUNITTESTINGID");
		HttpResponse response = httpclient.execute(httpget);
		HttpEntity entity = response.getEntity();
		char[] buf = new char[1024];
		StringBuffer str = new StringBuffer();
		if (entity != null) {
		    BufferedReader br = new BufferedReader(new InputStreamReader(entity.getContent()));
		    int read = br.read(buf);
		    while(read != -1) {
		    	str.append(buf, 0, read);
		    	read = br.read(buf);
		    }
		    br.close();
		}
		return str.toString();
	}
}
